package bme.andraskindler.treenventory.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
import android.view.View;
import android.widget.ImageView;

/**
 * Egy multitouch gesztusokkal és dupla klikkel is zoomolható vezérlőt testesít meg.
 * @author andraskindler
 *
 */
public class ZoomImageView extends ImageView {

	private Matrix mMatrix = new Matrix();

	private float mCurrentZoomLevel, mFitZoomLevel;
	private static final float MAX_ZOOM_LEVEL = 3.0f;
	private static final float ZOOM_FACTOR = 0.05f;
	private boolean mZoom;
	private int mWidth, mHeight;

	public ZoomImageView(Context context, final int width, final int height) {
		super(context);
		mWidth = width;
		mHeight = height;
	}

	/**
	 * Ez a függvény felel az inicializálásért, valamint a gesztusokat figyelő GestureDetector hozzákötéséért.
	 * @param bitmap
	 */
	public void init(final Bitmap bitmap) {
		setImageMatrix(mMatrix);
		setScaleType(ScaleType.MATRIX);
		mWidth = getWidth();
		mHeight = getHeight();
		fitImage(bitmap, mWidth, mHeight);

		mZoom = false;

		final GestureDetector detector = new GestureDetector(getContext(), new SimpleOnGestureListener() {

			@Override
			public boolean onDoubleTap(MotionEvent e) {
				if (mCurrentZoomLevel != mFitZoomLevel)
					fitImage(bitmap, mWidth, mHeight);
				else {
					mCurrentZoomLevel = MAX_ZOOM_LEVEL;
					mMatrix.setScale(mCurrentZoomLevel, mCurrentZoomLevel, e.getX(), e.getY());
					setImageMatrix(mMatrix);
					RectF r = new RectF();
					mMatrix.mapRect(r);
				}
				return true;
			}

			@Override
			public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
				mMatrix.postTranslate(-distanceX, -distanceY);
				setImageMatrix(mMatrix);

				return true;
			}

		});

		final ScaleGestureDetector scaledetector = new ScaleGestureDetector(getContext(), new SimpleOnScaleGestureListener() {

			private float mFocusX, mFocusY;

			@Override
			public boolean onScaleBegin(ScaleGestureDetector detector) {
				mFocusX = detector.getFocusX();
				mFocusY = detector.getFocusY();
				mZoom = true;
				return true;
			}

			@Override
			public boolean onScale(ScaleGestureDetector detector) {
				boolean zoom = false;
				if (detector.getScaleFactor() > 1.01f && mCurrentZoomLevel < MAX_ZOOM_LEVEL) {
					mCurrentZoomLevel += ZOOM_FACTOR;
					if (mCurrentZoomLevel > MAX_ZOOM_LEVEL)
						mCurrentZoomLevel = MAX_ZOOM_LEVEL;
					zoom = true;
				} else if (detector.getScaleFactor() < 0.99f && mCurrentZoomLevel > mFitZoomLevel) {
					mCurrentZoomLevel -= ZOOM_FACTOR;
					if (mCurrentZoomLevel < mFitZoomLevel)
						mCurrentZoomLevel = mFitZoomLevel;
					zoom = true;
				}

				if (zoom) {
					mMatrix.setScale(mCurrentZoomLevel, mCurrentZoomLevel, mFocusX, mFocusY);
					RectF r = new RectF();
					mMatrix.mapRect(r);
					if (r.top > 0 || r.left > 0)
						mMatrix.postTranslate(-r.left, -r.top + (((float) mHeight - (mFitZoomLevel * (float) bitmap.getHeight())) / 2f));

					setImageMatrix(mMatrix);
				}

				return true;
			}

			@Override
			public void onScaleEnd(ScaleGestureDetector detector) {
				super.onScaleEnd(detector);
				RectF r = new RectF();
				mMatrix.mapRect(r);
				mZoom = false;
			}

		});

		setOnTouchListener(new OnTouchListener() {

			public boolean onTouch(View v, MotionEvent event) {
				scaledetector.onTouchEvent(event);
				if (!mZoom)
					detector.onTouchEvent(event);
				return true;
			}
		});

	}

	/**
	 * A megadott méretnek megfelelően méretezi át a képet, hogy pont beleférjen a keretbe.
	 * 
	 * @param bitmap
	 * @param width
	 * @param height
	 */
	private void fitImage(final Bitmap bitmap, final int width, final int height) {
		setImageBitmap(bitmap);

		if (height / bitmap.getHeight() >= width / bitmap.getWidth())
			mFitZoomLevel = (float) width / (float) bitmap.getWidth();
		else
			mFitZoomLevel = (float) height / (float) bitmap.getHeight();

		mCurrentZoomLevel = mFitZoomLevel;

		float translateX = ((float) width - (mFitZoomLevel * (float) bitmap.getWidth())) / 2f;
		float translateY = ((float) height - (mFitZoomLevel * (float) bitmap.getHeight())) / 2f;
		mMatrix.setScale(mFitZoomLevel, mFitZoomLevel);
		mMatrix.postTranslate(translateX, translateY);
		setImageMatrix(mMatrix);
	}

	public ZoomImageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public ZoomImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public ZoomImageView(Context context) {
		super(context);
	}

}